Skip to content

chore(release): v1.8.1#266

Merged
Saul-Gomez-J merged 25 commits into
mainfrom
release/1.8.1
Apr 26, 2026
Merged

chore(release): v1.8.1#266
Saul-Gomez-J merged 25 commits into
mainfrom
release/1.8.1

Conversation

@Saul-Gomez-J
Copy link
Copy Markdown
Contributor

Summary

Promotes v1.8.1-beta.3 to the stable v1.8.1 release. Bumps package.json from 1.8.1-beta.31.8.1.

This consolidates 24 commits merged to develop since v1.8.0, validated via the beta channel (v1.8.1-beta.1beta.3). The macOS notarization issue that blocked beta.1 and beta.2 was resolved before beta.3 and the full asset matrix (4 macOS, 4 Linux, 3 Windows) is now publishing cleanly.

What's included

✨ Features

  • Cowork prerequisites: auto-provision PortableGit + Python (skip toast when already installed)
  • Projects: drag-and-drop folder selection in ProjectModal
  • MCP: canonicalize tool results, offload images to disk, image resize + output sanitization pipeline
  • File browser: replace header icons with an Add files modal
  • UI: background tool-call status, resilient preview tabs, hide streaming logo while todos are in progress
  • Chats: changing cwd in a chat now updates the parent project

🐛 Fixes

  • deps: pin minimatch@10.0.1 and brace-expansion@^2.0.2 to unbreak the CJS build
  • file-browser: normalize Windows paths before path-browserify
  • ai: drop redundant fallback in getProviderType
  • sidebar: list all project chats when entering project scope
  • mcp: PR feat(mcp): canonicalize tool results and offload images to disk #256 review fixes — image budget, text truncation, and 7 code quality items

🔧 Refactor

  • models: move selectable-models catalog to Zustand cache

Release pipeline

After merge, run /release from main to cut v1.8.1 (stable workflow Release Build & Publish).

Test plan

  • CI green on release/1.8.1
  • No regressions vs. v1.8.1-beta.3 (already validated by beta channel users)
  • After merge to main, run /release and confirm all 11 platform assets publish

🤖 Generated with Claude Code

Saul-Gomez-J and others added 25 commits April 14, 2026 16:55
Introduces image validation and resizing for MCP tool outputs with
per-provider limits, plus a shared tool output sanitizer to normalize
results across legacy and mcp-use services.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Introduce 'background' visual status for tool calls running as async tasks, with a new Activity icon and shared deriveToolCallVisualStatus helper.
- Strip ANSI escape sequences in sanitizeBinaryOutput so shell tool output renders cleanly.
- Rebuild web preview tabs from running tasks when push events are missed.
- Add unit tests for shell sanitization and tool-call status derivation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Restores the gate removed in the WIP commit so the BreathingLogo only
appears next to the running todo item, not duplicated below the list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
feat(local): optional API key for private local/OpenAI-compatible endpoints
Simplify the sidebar file browser header by removing the show/hide hidden
files toggle, manual refresh and inline add-files icon. Hidden files are
always shown, and a single "Add files" button next to the root label opens
a modal with a drop zone plus native file picker via webUtils.getPathForFile.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce CanonicalToolResultV1 as the single storage format for MCP
tool outputs. Image payloads are persisted on disk under
userData/tool-result-assets/images keyed by SHA-256, with the DB only
holding lightweight image-ref entries. Historical replay rebuilds the
model payload via tool.toModelOutput, keeping base64 out of the
sanitized message pipeline and compaction summaries. Assets are
reference-counted and cleaned up on session delete, message update,
and deleteMessagesAfter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… 7 code quality fixes

Issue 1 — toolMessageSanitizer: strip uiResources/images from legacy branch;
  fall back to '[Widget rendered]' when no recognized fields remain.

Issue 2 — chatService.mapMessageRow: normalize tool_calls in memory only,
  remove rewriteNormalizedToolCalls (no UPDATE on reads).

Issue 3 — aiService: guard logContextDiagnostics behind isEnabled('ai-sdk','debug');
  downgrade from info→debug; extract to contextDiagnostics.ts to avoid heavy
  import chain in tests.

Issue 4 — toolResultAssetStore: JSDoc on isAssetReferenced explaining LIKE scan safety.

Issue 5 — docs/HANDOFF: strip 29 absolute /Users/saulgomezjimenez/... paths.

Issue 6 — move getImageDimensions to imageResizer.ts; remove sharp import from
  toolResultAssetStore.

Issue 7 — miniChatWindow: extract mapPartsToPersistedToolCalls helper; fix shape
  bug where AI SDK parts were saved as-is instead of mapped to PersistedToolCall.

Option A — historicalToolReplayTools: HISTORICAL_IMAGE_BUDGET=2; pre-scan counts
  image-bearing results, oldest beyond budget are degraded to text via
  supportsVision:false, keeping O(1) images per turn instead of O(turns).

Option B — canonicalToolResultService: MAX_TOOL_TEXT_CHARS=30_000; truncate at
  materialize time (not storage), covering all text paths in canonical and legacy
  outputs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sidebar fetched a global top-50 via db.sessions.list and then filtered
by project_id on the client, so projects whose chats fell outside that
window appeared with only a subset. Replace that path with a scope-aware
fetch: when selectedProject is set, load via projects.getSessions (no
LIMIT), matching ProjectPage 1:1.

- chatStore: add refreshProjectSessions(projectId); make global list
  limit explicit ({ limit: 100, offset: 0 }); remove initializeChatStore
- App: effect reacts to selectedProject?.id and calls the correct
  refresh, replacing the mount-time initializeChatStore call

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`resolveModelTarget` already covers qualified and legacy raw refs in
standalone, platform pure, and platform hybrid modes. The manual catch
that re-scanned `preferencesService.providers` duplicated that logic and
silently masked real errors (corrupted refs, deleted providers).

Keep a single `try + warn + return undefined` so the only caller still
receives `undefined` on failure, and drop the dynamic preferencesService
import from the hot path.

Refs: #231

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move the unified `SelectableModelsResult` out of `useModelSelection`
local state into a new `catalogStore`, shared across all consumers:

- `catalogStore.ensureLoaded(params)` caches by
  (appMode, useOtherProviders, platformModels fingerprint), dedupes
  concurrent loads via `_inflight`, and only commits results when the
  cache key still matches at resolution time.
- `catalogStore.invalidate(reason)` clears the cache and auto-reloads
  with the last known params so subscribers refresh without needing to
  re-pass them.
- `useModelSelection` now subscribes to the store and derives
  `availableModels` / `groupedModelsByProvider` with `useMemo`; local
  `useState` + load effect removed. `handleModelChange` invalidates
  after `modelService.setActiveProvider` instead of setting two local
  arrays.
- `modelStore` invalidates on every provider mutation (initialize,
  setActiveProvider, updateProvider, syncProviderModels, toggle/set
  model selections, add/remove user model).
- `platformStore` invalidates after `ensureModelsLoaded` completes, on
  logout, on `setStandaloneMode`, on session-invalidated
  `refreshStatus`, and on unauthenticated/standalone init.

Fast navigation between chat and settings, or between sessions, no
longer recomputes the catalog; the loading flicker and race between
overlapping loads go away.

Refs: #231

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`path-browserify` is POSIX-only, so Windows paths with backslashes were
breaking `findNearestLoadedAncestor`, `pruneEntriesSubtree`, and the
drop/mention handlers in `PromptInputEditor`. Introduce a shared
`toPosixPath` helper and apply it before any `path.*` call; the original
path strings are preserved for keys and UI to avoid leaking POSIX-style
separators back into Windows state.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ensures Cowork mode always has a POSIX shell and Python available. On
the first Cowork-mode stream of the process, ensureCoworkPrerequisites
runs once and provisions:
  - Windows: Git Bash on PATH → Levante-managed PortableGit 2.47.0.2
    downloaded from git-for-windows and extracted to
    ~/levante/runtimes/gitbash/<version>/.
  - All platforms: Python 3.13 via python-build-standalone (needed by
    skill-creator and Python-based MCP servers).

Progress is broadcast to renderer via the new
levante/cowork/prerequisites-status IPC channel and surfaced as toasts
by the new CoworkPrerequisitesStatus component. Provisioning failure
is non-fatal — the bash tool falls back to the existing
auto-detection in getShellConfig.

The resolved shell path is passed down through
getCodingTools → BashTool → executeCommand/BackgroundTaskManager via a
new shellOverride option, avoiding re-detection on every command.

Also widens analytics runtime typing to the new RuntimeType union
(node|python|gitbash) and pins MCPDeepLinkModal's local type to
node|python since gitbash is not user-selectable there.

Adds unit tests for getShellConfig override behavior and
ensureCoworkPrerequisites fallback order.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Revamps the CWD selector in the create/edit project modal:

  - Replaces the "use custom folder" toggle with a two-option radio
    group: "New folder" (auto-generated under ~/levante/projects) vs
    "Existing folder" (user-selected path).
  - Adds a drop zone in "Existing folder" mode that accepts a folder
    dragged from the OS file browser. The resolved path is obtained
    via webUtils.getPathForFile (exposed as window.levante.fs.getPath\
ForFile) because File.path is deprecated in Electron 32+.
  - Validates the dropped item is actually a directory through a new
    levante/cowork/validate-directory IPC handler before accepting it.
  - Surfaces localized errors when the drop target is not a folder or
    the path cannot be read, and disables Save until a path is chosen
    in existing-folder mode.
  - Adds en/es strings for the new UI (cwd_mode_new,
    cwd_mode_existing, cwd_drop_zone, cwd_drop_zone_hint,
    cwd_drop_error_*, cwd_clear).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ect-dnd

feat: auto-provision Cowork prerequisites + drag-and-drop project folder
fix/refactor: sidebar scope, file browser, model catalog cache
feat(mcp): canonicalize tool results and offload images to disk
Emit the 'ensuring-python' progress event only when the Levante-managed
Python runtime is missing and needs to be provisioned. Previously the
event fired on every Cowork entry (first per process), causing a brief
toast flash on each app restart even though Python was already cached.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… CJS build

The overrides "minimatch: >=9.0.7" and "brace-expansion: >=5.0.5" forced an
incompatible combination: @electron/asar's nested minimatch@3 (CJS) cannot
require() brace-expansion@5.x (ESM-only), which broke `electron-forge make`
with `TypeError: expand is not a function` on every platform.

- minimatch → 10.0.1 (last version before the 10.0.2 breaking bump to
  brace-expansion@^4, which became ESM-only)
- brace-expansion → ^2.0.2 (CJS + ReDoS CVE fix)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lled-python

fix(cowork): skip ensuring-python toast when already installed
Promote 1.8.1-beta.3 to stable. Includes cowork prerequisites
auto-provisioning, MCP canonical tool results with image offloading,
project drag-and-drop, and several fixes across file-browser, sidebar
and AI provider handling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment on lines +9 to +17
import {
DEFAULT_NODE_VERSION,
DEFAULT_PYTHON_VERSION,
LEVANTE_DIR_NAME,
RUNTIME_DIR_NAME,
NODE_DIST_BASE_URL,
PORTABLE_GIT_ARCHIVE_X64,
PORTABLE_GIT_URL_X64,
} from './constants';
@Saul-Gomez-J Saul-Gomez-J merged commit c8df300 into main Apr 26, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants